package com.xuecheng.manage_cms.service;
import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsSite;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageResult;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.domain.cms.response.CmsTemplateResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import com.xuecheng.framework.model.response.ResponseResult;
import com.xuecheng.manage_cms.config.RabbitmqConfig;
import com.xuecheng.manage_cms.dao.CmsConfigRepository;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsSiteRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;


import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public class PageService {
    @Autowired
    private CmsPageRepository cmsPageRepository;

    //站点DAO
    @Autowired
    private CmsSiteRepository cmsSiteRepository;

    //模板DAO
    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;

    //轮播图
    @Autowired
    private CmsConfigRepository cmsConfigRepository;

    //操作文件
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //分页查询页面信息
    public QueryResponseResult findList( int page, int size, QueryPageResult queryPageResult){
        if(queryPageResult == null)  queryPageResult = new QueryPageResult();
        //设置值
        CmsPage cmsPage = new CmsPage();
        if(queryPageResult.getSiteId().equals("")) queryPageResult.setSiteId(" ");
        if(!" ".equals(queryPageResult.getSiteId()) && queryPageResult.getSiteId() != null)      cmsPage.setSiteId(queryPageResult.getSiteId());
        if(!" ".equals(queryPageResult.getTemplateId()) && queryPageResult.getTemplateId() != null)  cmsPage.setTemplateId(queryPageResult.getTemplateId());
        if(!" ".equals(queryPageResult.getPageAliase()) && queryPageResult.getPageAliase() != null )  cmsPage.setPageAliase(queryPageResult.getPageAliase().trim());

        //自定义匹配器
        ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("pageAliase",ExampleMatcher.GenericPropertyMatchers.contains());
        Example   example = Example.of(cmsPage,matcher);

        page = page <=0 ? 1:page-1;
        Pageable pageable = PageRequest.of(page,size);
        Page<CmsPage> all = cmsPageRepository.findAll(example,pageable);
        QueryResult<CmsPage> queryResult = new QueryResult<>();
        queryResult.setList(all.getContent());
        queryResult.setTotal(all.getTotalElements());
        QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
        return queryResponseResult;
    }

    //查询站点信息
    public List<CmsSite> findSiteList(){
        List<CmsSite> all = cmsSiteRepository.findAll();
        return all;
    }

    //  查询模板信息
    public List<CmsTemplate> findTemplateList(){
        List<CmsTemplate> all = cmsTemplateRepository.findAll();
        return all;
    }

    //添加页面     
    public CmsPageResult add(CmsPage cmsPage) { //校验页面是否存在，根据页面名称、站点Id、页面webpath查询                 
        CmsPage cmsPage1 = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if (cmsPage1 == null) {
            cmsPage.setPageId(null);//添加页面主键由spring data 自动生成             
            cmsPageRepository.save(cmsPage);//返回结果             
            CmsPageResult cmsPageResult = new CmsPageResult(CommonCode.SUCCESS, cmsPage);
            return cmsPageResult;
        }
        return new CmsPageResult(CommonCode.FAIL, null);
    }


    //根据Id查找页面
    public CmsPage findById(String id){
        Optional<CmsPage> cmsPage = cmsPageRepository.findById(id);
        CmsPage cms = null;
        if(cmsPage.isPresent()){
            cms = cmsPage.get();
            return cms;
        }
        return null;
    }

    //修改页面
    public CmsPageResult update(String id,CmsPage cmsPage){
        //
        CmsPage cms = this.findById(id);
        if(cms != null){
          //设置值
            cms.setSiteId(cmsPage.getSiteId());
            cms.setTemplateId(cmsPage.getTemplateId());
            cms.setPageName(cmsPage.getPageName());
            cms.setPageAliase(cmsPage.getPageAliase());
            cms.setPageWebPath(cmsPage.getPageWebPath());
            cms.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            cms.setDataUrl(cmsPage.getDataUrl());
            CmsPage save =cmsPageRepository.save(cms);
            CmsPageResult result = new CmsPageResult(CommonCode.SUCCESS,save);
            return result;
        }
        else{

            return  new CmsPageResult(CommonCode.FAIL,null);
        }
    }

    //删除页面
    public ResponseResult delete(String id){
        //删除之前验证是否存在
        Optional<CmsPage> byId = cmsPageRepository.findById(id);
        if(byId.isPresent()){
            cmsPageRepository.deleteById(id);
            return new ResponseResult(CommonCode.SUCCESS);
        }
        return new ResponseResult(CommonCode.FAIL);
      }

      //查询模板列表
      public QueryResponseResult findTemplateList( int page, int size, QueryPageResult queryPageResult){
          if(queryPageResult == null)  queryPageResult = new QueryPageResult();
          //设置值
          CmsTemplate template = new CmsTemplate();
          if(queryPageResult.getSiteId().equals(""))
              queryPageResult.setSiteId(" ");
          if(!" ".equals(queryPageResult.getSiteId()) && queryPageResult.getSiteId() != null)
              template.setSiteId(queryPageResult.getSiteId());
          if(!" ".equals(queryPageResult.getTemplateName()) && queryPageResult.getTemplateName() != null )
              template.setTemplateName(queryPageResult.getTemplateName().trim());

          //自定义匹配器
          ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("templateName",ExampleMatcher.GenericPropertyMatchers.contains());
          Example   example = Example.of(template,matcher);

          page = page <=0 ? 1:page-1;
          Pageable pageable = PageRequest.of(page,size);
          Page<CmsTemplate> all = cmsTemplateRepository.findAll(example,pageable);
          QueryResult<CmsTemplate> queryResult = new QueryResult<CmsTemplate>();
          queryResult.setList(all.getContent());
          queryResult.setTotal(all.getTotalElements());
          QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
          return queryResponseResult;
      }

      //添加模板
    public CmsTemplateResult add(CmsTemplate cmsTemplate){
        CmsTemplate template = cmsTemplateRepository.findByTemplateNameAndSiteIdAndTemplateParameter(cmsTemplate.getTemplateName(),cmsTemplate.getSiteId(),cmsTemplate.getTemplateParameter());
        if(template == null){
            cmsTemplate.setTemplateId(null);
            cmsTemplateRepository.save(cmsTemplate);
            return new CmsTemplateResult(CommonCode.SUCCESS,cmsTemplate);
        }
        return new CmsTemplateResult(CommonCode.FAIL,null);
    }


    //查询模板
    public CmsTemplate findTemplateById(String id){
        //验证是否存在记录
        Optional<CmsTemplate> byId = cmsTemplateRepository.findById(id);
        if(byId != null){
            CmsTemplate template = byId.get();
            return template;
        }
        return null;
    }

    //修改模板
    public CmsTemplateResult edit(String id,CmsTemplate cmsTemplate){
        //校验是否存在
        CmsTemplate template = this.findTemplateById(id);
        if(template != null){
            template.setSiteId(cmsTemplate.getSiteId());
            template.setTemplateName(cmsTemplate.getTemplateName());
            template.setTemplateParameter(cmsTemplate.getTemplateParameter());
            cmsTemplateRepository.save(template);
            return new CmsTemplateResult(CommonCode.SUCCESS,template);
        }
        return  new CmsTemplateResult(CommonCode.FAIL,null);
    }

    //删除模板数据
    public ResponseResult delTemplate(String id){
     //判断是否存在
        CmsTemplate template = this.findTemplateById(id);
        if(template != null){
            //删除
            cmsTemplateRepository.deleteById(id);
            return new ResponseResult(CommonCode.SUCCESS);
        }
        return new ResponseResult(CommonCode.FAIL);
    }

    //查询轮播图
    public CmsConfig getConfigById(String id){
        Optional<CmsConfig> cmsConfigs = cmsConfigRepository.findById(id);
        if(cmsConfigs.isPresent()){
            CmsConfig cmsConfig = cmsConfigs.get();
            return  cmsConfig;
        }
        return  null;
    }

    //页面静态化方法
    /**
     * 静态化程序获取页面的DataUrl
     *
     * 静态化程序远程请求DataUrl获取数据模型。
     *
     * 静态化程序获取页面的模板信息
     *
     * 执行页面静态化
     */
    public String getPageHtml(String pageId){

        //获取数据模型
        Map model = getModelByPageId(pageId);
        if(model == null){
            //数据模型获取不到
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }

        //获取页面的模板信息
        String template = getTemplateByPageId(pageId);
        if(StringUtils.isEmpty(template)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }

        //执行静态化
        String html = generateHtml(template, model);
        return html;

    }

    //执行静态化
    private String generateHtml(String templateContent,Map model ){
        //创建配置对象
        Configuration configuration = new Configuration(Configuration.getVersion());
        //创建模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",templateContent);
        //向configuration配置模板加载器
        configuration.setTemplateLoader(stringTemplateLoader);
        //获取模板
        try {
            Template template = configuration.getTemplate("template");
            //调用api进行静态化
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            return content;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    //获取页面的模板信息
    private String getTemplateByPageId(String pageId){
        //取出页面的信息
        CmsPage cmsPage = this.findById(pageId);
        if(cmsPage == null){
            //页面不存在
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //获取页面的模板id
        String templateId = cmsPage.getTemplateId();
        if(StringUtils.isEmpty(templateId)){
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //查询模板信息
        Optional<CmsTemplate> optional = cmsTemplateRepository.findById(templateId);
        if(optional.isPresent()){
            CmsTemplate cmsTemplate = optional.get();
            //获取模板文件id
            String templateFileId = cmsTemplate.getTemplateFileId();
            //从GridFS中取模板文件内容
            //根据文件id查询文件
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));

            //打开一个下载流对象
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            //创建GridFsResource对象，获取流
            GridFsResource gridFsResource = new GridFsResource(gridFSFile,gridFSDownloadStream);
            //从流中取数据
            try {
                String content = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
                return content;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;

    }


    //获取数据模型
    private Map getModelByPageId(String pageId){
        //取出页面的信息
        CmsPage cmsPage = this.findById(pageId);
        if(cmsPage == null){
            //页面不存在
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        //取出页面的dataUrl
        String dataUrl = cmsPage.getDataUrl();
        if(StringUtils.isEmpty(dataUrl)){
            //页面dataUrl为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        //通过restTemplate请求dataUrl获取数据
        ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = forEntity.getBody();
        return body;
    }

    //页面发布
    public ResponseResult post(String pageId){
        //执行页面静态化
        String pageHtml = this.getPageHtml(pageId);
        //将页面静态化文件存储到GridFS
        CmsPage cmsPage = saveHtml(pageId, pageHtml);
        //向MQ发消息
        sendPostPage(pageId);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    public CmsPage saveHtml(String pageId,String htmlContent){
        //得到页面的信息
        CmsPage cmsPage = this.findById(pageId);
        if(cmsPage == null ){
           ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        String pageName =cmsPage.getPageName();
        ObjectId fileId = null;
        InputStream inputStream = null;
        //将html文件内容保存到GridFs
        try {
             inputStream = IOUtils.toInputStream(htmlContent, "utf-8");
            //文件ID
             fileId = gridFsTemplate.store(inputStream, pageName);

        } catch (Exception e) {
            e.printStackTrace();
        }
        //保存信息
        cmsPage.setHtmlFileId(fileId.toHexString());
        cmsPageRepository.save(cmsPage);
        return cmsPage;
    }

    //向mq发送消息
    private void sendPostPage(String pageId){
     //品种消息对象
        CmsPage cmsPage = this.findById(pageId);
        Map<String,String> map = new HashMap<String,String>();
        map.put("pageId",pageId);
        String msg = JSON.toJSONString(map);
        //发送消息
        rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,cmsPage.getSiteId(),msg);
    }





}
